Mise à jour le 17/11/2021
Anti pattern Flag parameter

Anti pattern Flag parameter


Le flag parameter peut être considéré comme un anti-pattern.
Le principe est de passer un argument supplémentaire (le plus souvent de type boolean) à une méthode afin que celle-ci se comporte différemment selon ce paramètre.

Par exemple, supposons cette fonction :

function render(array $data, bool $flag)
{
    if ($flag) {
        // Premier comportement.
    } else {
        // Second comportement.
    }
}

// Code appelant
$data = getData();
$flag = getFlag();
render($data, $flag);


1. Solution 1 : découper la fonction en deux.

La fonction render doit être découpée en deux et c'est à l'appelant de ces fonctions de faire le if/else qui convient.

function firstRender(array $data)
{
    // Premier comportement.
}
function secondRender(array $data)
{
    // Second comportement.
}

// Code appelant
$data = getData();
$flag = getFlag();

if ($flag) {
    firstRender($data);
} else {
    secondRender($data);
}


2. Solution 2 : fusionner les deux paramètres

Si la fonction n'est pas simple à découper (plusieurs if/else interne). Même s'il conviendrait de la refactoriser, il peut être pertinent dans certaines conditions de faire porter la valeur du flag soit dans un objet que l'on transfère à la fonction, soit dans la classe qui contient la méthode.

2.1 Cas 1 : via un objet

class Renderer
{
    public function render(object $object)
    {
        $flag = $object->getFlag();
        // Suite des différentes conditions.
    }
}


2.2 Cas 2 : via un attribut de la classe

class Renderer
{
    protected bool $flag;

    function setFlag(bool $flag)
    {
        $this->flag = $flag;
    }

    function getFlag()
    {
        return $this->flag;
    }

    function render(object $object)
    {
        $flag = $this->getFlag();
        // Suite des différentes conditions.
    }
}


3. Solution 3 : créer plusieurs classes et une factory ou équivalent

Chaque classe possède un comportement propre. Ce comportement contient la logique selon le cas flag=true|false.
Le rôle de la Factory sera alors de fournir la bonne instance en fonction du paramètre flag.

// Code appelant
$rendererFactory = new RendererFactory();
$renderer = $rendererFactory->create($flag);
$renderer->render($data);


🧙‍♂️️Si la fonction existe déjà, il peut être long de tout refaire, il faut à ce moment là prendre un peu de temps de réflexion quant à l'intérêt de tout refaire pour un gain immédiat souvent faible.
Privilégier donc la réfacto des morceaux de code importants (à vous de définir cette importance en fonction du contexte).


4. Solution type Troll

🧙‍♂️️Cette solution n'est évidemment pas conseillée.


L'idée est de créer une instance Flag et de la passer à la fonction ; ainsi nous ne passons plus un boolean et donc nous sortons de l'anti-pattern.

<?php

class Flag
{
    protected bool $value;

    public function __construct(bool $value)
    {
        $this->value = $value;
    }

    public function isFalse(): bool
    {
        return !$this->isTrue();
    }

    public function isTrue(): bool
    {
        return true === $value;
    }
}

// Code appelant
$data = getData();
$flag = new Flag(true);
render($data, $flag);